/**
 * 中文WebSocket封装 (zh-websocket.js)
 * 支持WebSocket连接、消息发送、事件监听、重连机制、链式调用
 * 中文方法命名 + JSDoc 参数提示
 */

class WebSocket客户端 {
  /**
   * @param {string} url WebSocket服务器地址
   * @param {Object} 选项 配置选项
   * @param {string|string[]} 选项.协议 WebSocket协议
   * @param {number} 选项.重连间隔 重连间隔时间（毫秒）
   * @param {number} 选项.最大重连次数 最大重连次数
   * @param {Object} 选项.心跳配置 心跳配置
   */
  constructor(url, 选项 = {}) {
    this._url = url;
    this._选项 = {
      协议: [],
      重连间隔: 3000,
      最大重连次数: 5,
      心跳配置: {
        启用: false,
        间隔: 30000,
        消息: 'ping'
      },
      ...选项
    };
    
    this._连接 = null;
    this._重连次数 = 0;
    this._心跳定时器 = null;
    this._事件处理器 = new Map();
    this._状态 = WebSocket.CLOSED;
  }

  /**
   * 获取WebSocket连接实例
   * @returns {WebSocket|null} WebSocket连接实例，如果未连接则返回null
   */
  取值() {
    return this._连接;
  }

  /**
   * 获取当前连接状态码
   * @returns {number} 连接状态码（WebSocket.CONNECTING/CONNECTED/CLOSING/CLOSED）
   */
  获取状态() {
    return this._状态;
  }

  /**
   * 检查是否处于连接状态
   * @returns {boolean} 是否已连接
   */
  是否连接() {
    return this._状态 === WebSocket.OPEN;
  }

  /**
   * 连接WebSocket服务器
   * @returns {WebSocket客户端} 返回this以支持链式调用
   */
  连接() {
    try {
      // 关闭已存在的连接
      if (this._连接 && this._连接.readyState !== WebSocket.CLOSED) {
        this._连接.close();
      }

      // 创建新连接
      this._连接 = new WebSocket(this._url, this._选项.协议);
      
      // 设置事件处理器
      this._连接.onopen = (事件) => this._处理事件('连接', 事件);
      this._连接.onmessage = (事件) => this._处理事件('消息', 事件);
      this._连接.onerror = (事件) => this._处理事件('错误', 事件);
      this._连接.onclose = (事件) => this._处理事件('关闭', 事件);
      
    } catch (错误) {
      this._触发事件('错误', { 错误 });
    }
    
    return this;
  }

  /**
   * 发送消息
   * @param {string|Object} 消息 要发送的消息（字符串或可序列化对象）
   * @returns {WebSocket客户端} 返回this以支持链式调用
   */
  发送(消息) {
    if (this._状态 === WebSocket.OPEN) {
      try {
        const 发送数据 = typeof 消息 === 'string' ? 消息 : JSON.stringify(消息);
        this._连接.send(发送数据);
        this._触发事件('发送', { 消息 });
      } catch (错误) {
        this._触发事件('错误', { 错误, 消息 });
      }
    } else {
      this._触发事件('错误', { 错误: new Error('连接未建立'), 消息 });
    }
    
    return this;
  }

  /**
   * 发送JSON数据
   * @param {Object} 数据 要发送的JSON对象
   * @returns {WebSocket客户端} 返回this以支持链式调用
   */
  发送JSON(数据) {
    return this.发送(JSON.stringify(数据));
  }

  /**
   * 发送二进制数据
   * @param {ArrayBuffer|ArrayBufferView|Blob|string} 数据 要发送的二进制数据
   * @returns {WebSocket客户端} 返回this以支持链式调用
   */
  发送二进制(数据) {
    if (this._状态 === WebSocket.OPEN) {
      try {
        this._连接.send(数据);
        this._触发事件('发送', { 消息: 数据 });
      } catch (错误) {
        this._触发事件('错误', { 错误, 消息: 数据 });
      }
    }
    
    return this;
  }

  /**
   * 关闭连接
   * @param {number} [代码=1000] 关闭状态码
   * @param {string} [原因=''] 关闭原因
   * @returns {WebSocket客户端} 返回this以支持链式调用
   */
  关闭(代码 = 1000, 原因 = '') {
    if (this._连接 && (this._状态 === WebSocket.OPEN || this._状态 === WebSocket.CONNECTING)) {
      this._停止心跳();
      this._连接.close(代码, 原因);
      this._重连次数 = 0;
    }
    
    return this;
  }

  /**
   * 添加事件监听
   * @param {string} 事件名 事件名称（连接、消息、错误、关闭、重连尝试、发送）
   * @param {Function} 回调 事件处理函数
   * @returns {WebSocket客户端} 返回this以支持链式调用
   */
  监听(事件名, 回调) {
    if (!this._事件处理器.has(事件名)) {
      this._事件处理器.set(事件名, new Set());
    }
    this._事件处理器.get(事件名).add(回调);
    return this;
  }

  /**
   * 移除事件监听
   * @param {string} 事件名 事件名称
   * @param {Function} [回调] 事件处理函数，不传则移除该事件的所有监听器
   * @returns {WebSocket客户端} 返回this以支持链式调用
   */
  取消监听(事件名, 回调) {
    if (this._事件处理器.has(事件名)) {
      if (回调) {
        this._事件处理器.get(事件名).delete(回调);
      } else {
        this._事件处理器.delete(事件名);
      }
    }
    return this;
  }

  /**
   * 内部方法：处理WebSocket事件
   * @private
   * @param {string} 事件名 事件名称
   * @param {Event} 事件 原始事件对象
   */
  _处理事件(事件名, 事件) {
    this._状态 = this._连接.readyState;
    
    // 根据事件类型处理特定逻辑
    switch (事件名) {
      case '连接':
        this._重连次数 = 0;
        this._触发事件('连接', { 事件 });
        this._启动心跳();
        break;
        
      case '消息':
        let 数据;
        try {
          // 尝试解析为JSON
          数据 = JSON.parse(事件.data);
        } catch {
          // 不是JSON则保持原样
          数据 = 事件.data;
        }
        this._触发事件('消息', { 原始事件: 事件, 数据, 原始数据: 事件.data });
        break;
        
      case '关闭':
        this._停止心跳();
        this._触发事件('关闭', { 事件 });
        
        // 尝试重连
        if (this._选项.最大重连次数 === -1 || this._重连次数 < this._选项.最大重连次数) {
          setTimeout(() => {
            this._重连次数++;
            this._触发事件('重连尝试', { 次数: this._重连次数 });
            this.连接();
          }, this._选项.重连间隔);
        }
        break;
        
      case '错误':
        this._触发事件('错误', { 事件 });
        break;
    }
  }

  /**
   * 内部方法：触发事件
   * @private
   * @param {string} 事件名 事件名称
   * @param {Object} 数据 事件数据
   */
  _触发事件(事件名, 数据) {
    if (this._事件处理器.has(事件名)) {
      for (const 回调 of this._事件处理器.get(事件名)) {
        try {
          回调(数据);
        } catch (错误) {
          console.error(`WebSocket事件处理器错误 [${事件名}]:`, 错误);
        }
      }
    }
  }

  /**
   * 内部方法：启动心跳机制
   * @private
   */
  _启动心跳() {
    if (this._选项.心跳配置.启用 && !this._心跳定时器) {
      this._心跳定时器 = setInterval(() => {
        if (this._状态 === WebSocket.OPEN) {
          this.发送(this._选项.心跳配置.消息);
        }
      }, this._选项.心跳配置.间隔);
    }
  }

  /**
   * 内部方法：停止心跳机制
   * @private
   */
  _停止心跳() {
    if (this._心跳定时器) {
      clearInterval(this._心跳定时器);
      this._心跳定时器 = null;
    }
  }

  /**
   * 获取发送缓冲区大小
   * @returns {number} 缓冲区中的字节数
   */
  获取缓冲大小() {
    return this._连接 ? this._连接.bufferedAmount : 0;
  }

  /**
   * 升级连接协议（注意：WebSocket本身不支持运行时升级协议）
   * @param {string|string[]} 协议 新的协议
   * @returns {WebSocket客户端} 返回this以支持链式调用
   */
  升级协议(协议) {
    if (this._连接 && this._状态 === WebSocket.OPEN) {
      // WebSocket本身不支持运行时升级协议，这里只是提供接口
      this._触发事件('错误', { 错误: new Error('WebSocket不支持运行时升级协议') });
    }
    return this;
  }

  /**
   * 手动触发重连
   * @returns {WebSocket客户端} 返回this以支持链式调用
   */
  重连() {
    this._重连次数 = 0;
    this.close();
    this.连接();
    return this;
  }

  /**
   * 设置重连配置
   * @param {Object} 配置 重连配置对象
   * @param {number} [配置.重连间隔] 重连间隔时间（毫秒）
   * @param {number} [配置.最大重连次数] 最大重连次数（-1表示无限重连）
   * @returns {WebSocket客户端} 返回this以支持链式调用
   */
  设置重连配置(配置) {
    this._选项 = {
      ...this._选项,
      ...配置
    };
    return this;
  }

  /**
   * 设置心跳配置
   * @param {Object} 配置 心跳配置对象
   * @param {boolean} [配置.启用] 是否启用心跳
   * @param {number} [配置.间隔] 心跳间隔（毫秒）
   * @param {string} [配置.消息] 心跳消息内容
   * @returns {WebSocket客户端} 返回this以支持链式调用
   */
  设置心跳配置(配置) {
    this._选项.心跳配置 = {
      ...this._选项.心跳配置,
      ...配置
    };
    
    // 重启心跳
    if (this._状态 === WebSocket.OPEN) {
      this._停止心跳();
      this._启动心跳();
    }
    
    return this;
  }

  /** 静态方法 */

  /**
   * 检查浏览器是否支持WebSocket
   * @static
   * @returns {boolean} 是否支持WebSocket
   */
  static 是否支持() {
    return 'WebSocket' in window;
  }

  /**
   * 创建安全的WebSocket URL（自动转换协议）
   * @static
   * @param {string} 基础URL 基础URL地址
   * @param {Object} [参数={}] 要添加的查询参数
   * @returns {string} 转换后的WebSocket URL
   */
  static 创建安全URL(基础URL, 参数 = {}) {
    const url = new URL(基础URL);
    
    // 自动切换协议：http -> ws, https -> wss
    if (url.protocol === 'http:') {
      url.protocol = 'ws:';
    } else if (url.protocol === 'https:') {
      url.protocol = 'wss:';
    }
    
    // 添加参数
    for (const [键, 值] of Object.entries(参数)) {
      url.searchParams.set(键, 值);
    }
    
    return url.toString();
  }
}

// 规范导出
export { WebSocket客户端 };
export default WebSocket客户端;